﻿using System;
using System.Collections.Generic;
using System.Globalization;
using TLV.RestrictionsValidation.analysis;
using TLV.RestrictionsValidation.node;

namespace TLV.RestrictionsValidation
{
    class ExpressionEvaluator : DepthFirstAdapter
    {
        private bool? result = null;
        private Stack<bool> stack = new Stack<bool>();

        public bool CalculatedResult
        {
            get
            {
                if (result == null)
                    throw new InvalidOperationException("Must apply ExpressionCalculator to the AST first.");

                return result.Value;
            }
        }

        public override void OutStart(Start node)
        {
            if (stack.Count != 1)
                throw new Exception("Stack should contain only one element at end.");

            result = stack.Pop();
        }

        public override void OutAOrExp(AOrExp node)
        {
            bool operandA = stack.Pop();
            bool operandB = stack.Pop();
            stack.Push(operandA || operandB);
        }

        public override void OutAAndExp(AAndExp node)
        {
            bool operandA = stack.Pop();
            bool operandB = stack.Pop();
            stack.Push(operandA && operandB);
        }

        public override void OutAEqualsStringExp(AEqualsStringExp node)
        {
            string fieldValue = ValuesDictionary.GetString(((AStringExp)node.GetLeft()).GetString().Text);
            string value = ((AStringExp)node.GetRight()).GetString().Text;
            stack.Push(fieldValue == value);
        }

        public override void OutAEqualsNumberExp(AEqualsNumberExp node)
        {
            double fieldValue = ValuesDictionary.GetNumber(((AStringExp)node.GetLeft()).GetString().Text);
            double number = Convert.ToDouble(((ANumberExp)node.GetRight()).GetNumber().Text);
            stack.Push(fieldValue == number);
        }

        public override void OutANotEqualsStringExp(ANotEqualsStringExp node)
        {
            string fieldValue = ValuesDictionary.GetString(((AStringExp)node.GetLeft()).GetString().Text);
            string value = ((AStringExp)node.GetRight()).GetString().Text;
            stack.Push(fieldValue != value);
        }

        public override void OutANotEqualsNumberExp(ANotEqualsNumberExp node)
        {
            double fieldValue = ValuesDictionary.GetNumber(((AStringExp)node.GetLeft()).GetString().Text);
            double number = Convert.ToDouble(((ANumberExp)node.GetRight()).GetNumber().Text);
            stack.Push(fieldValue != number);
        }

        public override void OutAGreaterThanExp(AGreaterThanExp node)
        {
            double fieldValue = ValuesDictionary.GetNumber(((AStringExp)node.GetLeft()).GetString().Text);
            double number = Convert.ToDouble(((ANumberExp)node.GetRight()).GetNumber().Text);
            stack.Push(fieldValue > number);
        }

        public override void OutASmallerThanExp(ASmallerThanExp node)
        {
            double fieldValue = ValuesDictionary.GetNumber(((AStringExp)node.GetLeft()).GetString().Text);
            double number = Convert.ToDouble(((ANumberExp)node.GetRight()).GetNumber().Text);
            stack.Push(fieldValue < number);
        }

        public override void OutAGreaterEqualsExp(AGreaterEqualsExp node)
        {
            double fieldValue = ValuesDictionary.GetNumber(((AStringExp)node.GetLeft()).GetString().Text);
            double number = Convert.ToDouble(((ANumberExp)node.GetRight()).GetNumber().Text);
            stack.Push(fieldValue >= number);
        }

        public override void OutASmallerEqualsExp(ASmallerEqualsExp node)
        {
            double fieldValue = ValuesDictionary.GetNumber(((AStringExp)node.GetLeft()).GetString().Text);
            double number = Convert.ToDouble(((ANumberExp)node.GetRight()).GetNumber().Text);
            stack.Push(fieldValue <= number);
        }
    }
}